package au.edu.adelaide.mips_soft_core.board_interface_pc.core;

import java.util.ArrayList;

import au.edu.adelaide.adept_sdk_java.AdeptSDKJava;
import au.edu.adelaide.adept_sdk_java.AdeptSDKJava.DVC;
import au.edu.adelaide.mips_soft_core.board_interface_pc.logger.Logger;

public class Core {
	
	//Stuff for logger
	public static final int LOG_LEVEL_MESSAGE = 1;
	public static final int LOG_LEVEL_WARNING = 2;
	public static final int LOG_LEVEL_ERROR = 3;
	
	Logger logger = new Logger(new int[]{LOG_LEVEL_MESSAGE, LOG_LEVEL_WARNING, LOG_LEVEL_ERROR}, new String[]{"Message", "Warning", "Error"});
	
	//list of connected devices
	private ArrayList<Device> devices = new ArrayList<Device>();
	
	//core listeners
	private ArrayList<CoreListener> listeners = new ArrayList<CoreListener>();
	
	private Core(){
		//start polling the Digilent api for connected devices
		this.startDeviceFinder();
		
		//This is to allow automatic disconnection from device when application closed
		Runtime.getRuntime().addShutdownHook(new Thread(){
			
			public void run(){
				shutdown();
			}
			
		});
	}
	
	//get the Core logger
		public Logger getLogger(){
			return this.logger;
		}
	
	
	
	public void shutdown(){
		this.deviceFinding = false;
		for(int i = 0; i < devices.size(); i++){
			Device device = devices.get(i);
			if(devices.get(i).status != Device.Status.DISCONNECTED){
				device.disconnectBlocking(false);
			}
		}
		
	}
	
	/**
	 * Gets the number of connected devices
	 * @return
	 */
	public int getNumberOfDevices(){
		return this.devices.size();
	}
	
	/**
	 * Gets the device at the chosen index
	 * @param index
	 * @return
	 */
	public Device getDevice(int index){
		return this.devices.get(index);
	}
	
	public void addCoreListener(CoreListener listener){
		listeners.add(listener);
	}
	
	public void removeCoreListener(CoreListener listener){
		listeners.remove(listener);
	}
	
	
	void deviceConnected(Device device){
		for(int i = 0; i < listeners.size(); i++){
			listeners.get(i).deviceConnected(device);
		}
		device.downloadInfo();
	}
	
	void deviceDisconnected(Device device){
		for(int i = 0; i < listeners.size(); i++){
			listeners.get(i).deviceDisconnected(device);
		}
	}
	
	private static Core coreInstance = new Core();
	
	public static Core getCore(){
		return coreInstance;
	}
	
	boolean deviceFinding = false;
	
	
	Thread finderThread;
	boolean finderThreadRunning = false;
	Object sync = new Object();
	
	
	
	public void startDeviceFinder(){
		deviceFinding = true;
		synchronized(sync){
			if(finderThreadRunning){
				return;
			}
			finderThreadRunning = true;
			finderThread = new Thread("Device Finder"){
				
				public void run(){
					while(deviceFinding){
						int[] countArr = new int[1];
						AdeptSDKJava.getInstance().jDmgrEnumDevices(countArr);
						int count = countArr[0];
						DVC dvc = AdeptSDKJava.getInstance().createDVCHandle();
						ArrayList<Device> newList = new ArrayList<Device>();
						int newDevice = 0;
						for(int i = 0; i < count; i++){
							AdeptSDKJava.getInstance().jDmgrGetDvc(i, dvc);
							String name = dvc.getSzName();
							String connectionString = dvc.getszConn();
							Device device = removeDevice(name, connectionString);
							
							if(device == null){
								device = new Device(name, connectionString);
								newDevice++;
							}
							newList.add(device);
							
						}
						AdeptSDKJava.getInstance().jDmgrFreeDvcEnum();
						dvc.dispose();
						boolean change =( devices.size() > 0) || (newDevice > 0);
						devices = newList;
						if(change){
							for(int i = 0; i < listeners.size(); i++){
								listeners.get(i).deviceListChanged();
							}
						}
						try{
							Thread.sleep(500);
						}catch(Exception ex){
							
						}
					}
					synchronized(sync){
						finderThreadRunning = false;
					}
				}
			};
			finderThread.start();
		}
		
	}
	
	public Device removeDevice(String name, String connectionString){
		for(int i = 0; i < this.devices.size(); i++){
			Device device = this.devices.get(i);
			if(device.name.equals(name) && device.connectionString.equals(connectionString)){
				this.devices.remove(i);
				return device;
			}
		}
		return null;
	}

}
